import { Injectable } from '@angular/core';
import { TreeNode } from '@farris/ui-treetable';
import { NotifyService } from '@farris/ui-notify';
import { DomService, DesignViewModelService, DesignerHostSettingService, DgControl, SchemaService, FormBasicService, DesignerEnvType } from '@farris/designer-services';
import { IControlService } from '@farris/designer-element';
import { FieldTreeBuilder } from '../field-tree-builder.service';

@Injectable()
export class FieldTreeTableService {

  private controlServ: IControlService;
  private controlCreatorServ: any;
  private schemaDOMMapping: any;

  controlsInfo: any = {};
  viewModelId: string;

  private fieldTreeBuilder: FieldTreeBuilder;

  constructor(
    private designerHostSettingService: DesignerHostSettingService,
    private domServ: DomService,
    private dgVMServ: DesignViewModelService,
    private schemaServ: SchemaService,
    private formBasicServ: FormBasicService,
    private notifyServ: NotifyService) {

    this.schemaDOMMapping = this.designerHostSettingService.designerHost.getService('SchemaDOMMapping');
    this.controlServ = this.designerHostSettingService.designerHost.getService('ControlService');
    this.controlCreatorServ = this.designerHostSettingService.designerHost.getService('ControlCreatorService');
  }

  buildFieldTreeData(viewModelId: string) {
    this.fieldTreeBuilder = new FieldTreeBuilder(this.schemaDOMMapping, this.dgVMServ, this.domServ, this.formBasicServ);

    const treeData = this.fieldTreeBuilder.buildFieldTreeData(viewModelId);
    this.controlsInfo = this.fieldTreeBuilder.controlsInfo;
    return treeData;
  }

  /**
   * 刷新表单DOM
   * @param viewModelId VMID
   */
  refreshDOM(viewModelId: string, treeData: TreeNode[] | any[]) {
    const cmp = this.domServ.getComponentByVMId(viewModelId);
    switch (cmp.componentType) {
      case 'dataGrid': {
        this.refreshGridControls(treeData, viewModelId);
        break;
      }
      default: {
        if (cmp.componentType.startsWith('form') || this.formBasicServ.envType === 'mobileDesigner') {
          this.refreshFormControls(treeData, cmp.componentType, viewModelId);
        }
      }
    }

  }

  /**
   * Form类型的组件，重组内容
   */
  private refreshFormControls(treeData: TreeNode[] | any[], componentType: string, viewModelId: string) {
    const newDomContents = [];
    const { controls: oldControls, formLayout } = this.controlsInfo;
    const cmpNode = this.domServ.getComponentByVMId(viewModelId);
    treeData.forEach((element: TreeNode | any) => {
      // 没有绑定信息的控件：原样塞回
      if (element.isNoBinding) {
        newDomContents.push(element.control);
        return;
      }
      if (element.control && element.control.type === DgControl.FieldSet.type) {
        // return;
      }

      const field = element.data;
      let oldControlDom: any = oldControls.find(c => c.binding && c.binding.field === field.id);

      // 分组节点
      if (element.isGroupNode) {
        oldControlDom = oldControls.find(c => c.id === element.id);
        if (oldControlDom) {
          oldControlDom.contents = [];
          newDomContents.push(oldControlDom);
        } else {
          const fieldSetMetadata = this.controlServ.getControlMetaData(DgControl.FieldSet.type);
          if (!fieldSetMetadata) { return; }
          fieldSetMetadata.id = field.id;
          fieldSetMetadata.title = field.name;
          fieldSetMetadata.contents = [];
          fieldSetMetadata.appearance = { class: 'col-12 px-0' };

          // 运行时定制新增控件：增加isRTControl的标识
          if (this.formBasicServ.envType === DesignerEnvType.runtimeCustom) {
            fieldSetMetadata.isRTControl = true;
          }


          oldControlDom = fieldSetMetadata;
          newDomContents.push(fieldSetMetadata);
          oldControls.push(fieldSetMetadata);
        }

        element.children.forEach(childNode => {
          const oldChildControlDom = oldControls.find(c => c.binding && c.binding.field === childNode.data.id);
          // 新增控件
          if (!oldChildControlDom) {
            let metadata;
            if (childNode.isBindVariable) {
              metadata = this.controlCreatorServ.createControlByVariable(childNode.data, componentType, null, cmpNode.id);
            } else {
              metadata = this.controlCreatorServ.createControlBySchemaFeild(childNode.data, componentType, null, cmpNode.id);
            }
            if (metadata) {
              oldControlDom.contents.push(metadata);
              oldControls.push(metadata);
            }
          } else {
            oldControlDom.contents.push(oldChildControlDom);
          }
        });

        return;
      }

      // 平铺字段
      if (!oldControlDom) {
        let metadata;
        if (element.isBindVariable) {
          metadata = this.controlCreatorServ.createControlByVariable(field, componentType, null, cmpNode.id);
        } else {
          metadata = this.controlCreatorServ.createControlBySchemaFeild(field, componentType, null, cmpNode.id);
        }
        if (metadata) {
          newDomContents.push(metadata);
          oldControls.push(metadata);
        }
      } else {
        newDomContents.push(oldControlDom);
      }
    });

    // 重置组件dom结构
    formLayout.contents = newDomContents;
  }


  /**
   * 表格类型的组件，重组内容
   */
  private refreshGridControls(treeData: TreeNode[] | any[], viewModelId: string) {
    const { controls: gridFields, formLayout } = this.controlsInfo;
    if (!formLayout) {
      return;
    }
    const fieldEditable = formLayout.fieldEditable;
    const gridType = formLayout.type;
    const gridFieldType = gridType === DgControl.DataGrid.type ? DgControl.GridField.type : DgControl.TreeGridField.type;

    const newDomContents = [];
    treeData.forEach(element => {
      const oldControlDom = gridFields.find(f => f.binding && f.binding.field === element.data.id);

      // 平铺字段
      if (!oldControlDom) {
        let dataField = element.data.bindingPath;
        // 对于很旧的表单schema缺少bindingPath属性，故重新获取bindingPath
        if (!dataField) {
          const { isRefElement, refElementLabelPath } = this.schemaServ.getFieldByIDAndVMID(element.data.id, viewModelId);
          dataField = isRefElement ? refElementLabelPath : element.data.label; // 关联字段dataField
        }

        const metadata = this.controlCreatorServ.createGridFieldBySchemaFeild(
          element.data, dataField, fieldEditable, gridFieldType, formLayout.controlSource);
        if (metadata) {
          newDomContents.push(metadata);
          gridFields.push(metadata);
        }
      } else {
        newDomContents.push(oldControlDom);
      }
    });

    // 更新组件dom结构
    formLayout.fields = newDomContents;

  }


  /**
   * 上移
   * 若当前节点是分组节点内的第一个节点，则移出分组，放在分组上面；  字段移出分组后判断分组下的节点是否为空，若空则删除分组
   * 若上个节点是分组节点，则移动到分组内
   * 当前是分组节点，只在根节点下移动（不支持嵌套分组）
   *
   * 方法返回VM字段的变更集
   */
  moveUp(selectedNode: any, treeData: any) {

    const parentNode = selectedNode.parent;
    const parentData = parentNode ? parentNode.children : treeData; // 在根节点上移动 or 分组节点上移动
    const index = parentData.findIndex(node => node.data.id === selectedNode.data.id);
    // 1、顶级节点 ====> 不动
    if (index < 1 && !parentNode) {
      return;
    }
    const vmChanges = {};
    // 2、分组节点内的第一个节点 ===> 移出分组
    if (index < 1 && parentNode && parentNode.isGroupNode) {
      parentData.splice(0, 1);
      const parentIndex = treeData.findIndex(node => node.data.id === parentNode.data.id);
      selectedNode.parent = null;
      treeData.splice(parentIndex, 0, selectedNode);
      vmChanges[selectedNode.id] = {
        groupId: null,
        groupName: null
      };
      // 分组下没有字段了: 删除分组
      if (parentData.length === 0) {
        treeData.splice(parentIndex + 1, 1);
      }
    } else {
      const preEle = parentData[index - 1];
      parentData.splice(index, 1);

      if (preEle.children && preEle.children.length > 0 && !selectedNode.isGroupNode) {
        // 3、上一个节点是分组且当前不是分组节点 ===> 移动到分组内
        selectedNode.parent = preEle;
        preEle.children.push(selectedNode);
        vmChanges[selectedNode.id] = {
          groupId: preEle.data.id,
          groupName: preEle.data.name
        };
      } else {
        // 4、同级移动
        parentData.splice(index - 1, 0, selectedNode);
      }
    }

    return vmChanges;

  }

  /**
   * 下移
   * 若当前节点是分组节点内的最后一个节点，则移出分组，放在分组下面；  字段移出分组后判断分组下的节点是否为空，若空则删除分组
   * 若下个节点是分组节点，则移动到分组内
   * 当前是分组节点，只在根节点下移动（不支持嵌套分组）
   *
   * 方法返回VM字段的变更集
   */
  moveDown(selectedNode: any, treeData: any) {
    const parentNode = selectedNode.parent;
    const parentData = parentNode ? parentNode.children : treeData; // 在根节点上移动 or 分组节点上移动
    const index = parentData.findIndex(node => node.data.id === selectedNode.data.id);
    // 1、顶级节点的最后一个====> 不动
    if (index === parentData.length - 1 && !parentNode) {
      return;
    }
    // 记录涉及VM字段的变化
    const vmChanges = {};

    // 2、分组节点内的最后一个节点 ====> 移出分组
    if (index === parentData.length - 1 && parentNode && parentNode.isGroupNode) {
      parentData.splice(index, 1);
      selectedNode.parent = null;
      const parentIndex = treeData.findIndex(node => node.data.id === parentNode.data.id);
      treeData.splice(parentIndex + 1, 0, selectedNode);
      vmChanges[selectedNode.id] = {
        groupId: null,
        groupName: null
      };
      // 分组下没有字段了: 删除分组
      if (parentData.length === 0) {
        treeData.splice(parentIndex, 1);
      }
    } else {
      const nextEle = parentData[index + 1];

      parentData.splice(index, 1);
      // 3、下一个节点是分组且当前不是分组节点 ===> 移动到分组内
      if (nextEle.children && nextEle.children.length > 0 && !selectedNode.isGroupNode) {
        nextEle.children.splice(0, 0, selectedNode);
        selectedNode.parent = nextEle;
        vmChanges[selectedNode.id] = {
          groupId: nextEle.data.id,
          groupName: nextEle.data.name
        };
      } else {
        // 4、同级移动
        parentData.splice(index + 1, 0, selectedNode);
      }
    }

    return vmChanges;
  }

  /**
   * 移除字段
   * @param checkeds 勾选中的节点
   * @param treeData 树数据
   * @param selectedNodeId 当前行选中记录id
   */
  removeFields(checkeds: any, treeData: any, selectedNodeId: string) {

    let removeSelectedNode = false;

    checkeds.forEach(element => {
      // 跳过分组节点
      if (element.isGroupNode) {
        return;
      }
      // 在根节点下删除
      if (!element.parent) {
        const nodeIndex = treeData.findIndex(node => node.data.id === element.data.id);
        treeData.splice(nodeIndex, 1);
      } else {
        // 分组节点下删除
        const nodeIndex = element.parent.children.findIndex(node => node.data.id === element.data.id);
        element.parent.children.splice(nodeIndex, 1);

        // 分组节点下没有字段则自动删除分组节点
        if (element.parent.children.length === 0) {
          const groupId = treeData.findIndex(node => node.data.id === element.parent.data.id);
          treeData.splice(groupId, 1);
        }
      }
      // 若当前节点为行选中节点，需要清空选中行记录
      if (element.data.id === selectedNodeId) {
        removeSelectedNode = true;
      }

      // 删除当前controls集合中的节点
      if (this.controlsInfo && this.controlsInfo.controls && this.controlsInfo.controls.length) {
        this.controlsInfo.controls = this.controlsInfo.controls.filter(c =>
          (c.binding && c.binding.field !== element.data.id) && c.id !== element.data.id);
      }

    });
    return removeSelectedNode;
  }


  /**
   * 解除分组
   * @param checkeds 勾选中的节点
   * @param treeData 树数据
   */
  removeGroup(checkeds: TreeNode[] | any[], treeData: any) {
    const selectedIdList = [];
    for (const element of checkeds) {
      // 1、分组下的节点：父节点未选中时，从分组中移除并添加到根节点；若父节点已选中，则跳过
      if (element.parent && element.children.length === 0) {
        const isParentSelected = checkeds.findIndex(se => se.data.id === element.parent.data.id);
        if (isParentSelected < 0) {
          const nodeIndex = element.parent.children.findIndex(node => node.data.id === element.data.id);
          element.parent.children.splice(nodeIndex, 1);
          treeData.push({ data: element.data, children: [], isBindVariable: element.isBindVariable });

          if (element.parent.children.length === 0) {
            const groupId = treeData.findIndex(node => node.data.id === element.parent.data.id);
            treeData.splice(groupId, 1);
          }

          selectedIdList.push(element.data.id);
        }
      }

      // 2、分组节点：移除分组节点并将其下的节点移动到根节点下
      if (element.isGroupNode) {
        const groupNodeIndex = treeData.findIndex(treeNode => treeNode.data.id === element.data.id);
        treeData.splice(groupNodeIndex, 1);

        element.children.map(treeNode => {
          treeData.push({ data: treeNode.data, children: [], isBindVariable: treeNode.isBindVariable });
          selectedIdList.push(treeNode.data.id);
        });
      }

      // 3、根节点下未分组的字段：给出提示
      if (!element.parent && !element.isGroupNode) {
        this.notifyServ.warning('字段【' + element.data.name + '】未分组！');
      }

      element.parent = null;
    }

    return selectedIdList;
  }

}
